package fr.inserm.u915.tabixserver;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

import fr.inserm.u915.tabixserver.expr.Context;
import fr.inserm.u915.tabixserver.expr.ExprNode;

public class MappedObject
	implements Comparable<MappedObject>
	{
	private String tokens[];
	private Instance instance;
	MappedObject(Instance instance,String tokens[])
		{
		this.instance=instance;
		this.tokens=tokens;
		}
	public Instance getInstance()
		{
		return instance;
		}
	public Table getTable()
		{
		return getInstance().getTable();
		}
	public String[] getTokens()
		{
		return this.tokens;
		}
	
	public String get(int i)
		{
		return getTokens()[i];
		}
	
	public String getName()
		{
		Column c=getTable().getNameColumn();
		if(c==null) return getSegment().toString();
		return get(c.getColumnIndex());
		}
	
	public String getChromosome()
		{
		return get(getTable().getChromColumn().getColumnIndex());
		}
	public int getStart()
		{
		return Integer.parseInt(get(getTable().getStartColumn().getColumnIndex()));
		}
	
	public int getEnd()
		{
		return Integer.parseInt(get(getTable().getEndColumn().getColumnIndex()));
		}
	
	public Strand getStrand()
		{
		Column c=getTable().getStrandColumn();
		if(c==null || c.getColumnIndex()>=tokens.length) return Strand.UNKNOWN;
		String s=tokens[c.getColumnIndex()];
		if(s.equals("+") || s.equalsIgnoreCase("plus") || s.equalsIgnoreCase("forward") )
			{
			return Strand.PLUS;
			}
		if(s.equals("-") || s.equalsIgnoreCase("minus") || s.equalsIgnoreCase("reverse") )
			{
			return Strand.MINUS;
			}
		return Strand.UNKNOWN;
		}
	
	public Segment getSegment()
		{	
		return new Segment(getChromosome(), getStart(), getEnd());
		}
	@Override
	public int compareTo(MappedObject o)
		{
		return getSegment().compareTo(o.getSegment());
		}
	
	@Override
	public int hashCode()
		{
		final int prime = 31;
		int result = 1;
		result = prime * result + instance.getId().hashCode();
		result = prime * result + instance.getBuild().getId().hashCode();
		result = prime * result + Arrays.hashCode(tokens);
		return result;
		}
	
	@Override
	public boolean equals(Object obj)
		{
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		MappedObject other = (MappedObject) obj;
		if (instance != other.instance ) return false;
		return Arrays.equals(tokens, other.tokens);
		}
		
	Map<String, String> getMap()
		{
		Map<String, String> m=new LinkedHashMap<String, String>();
		for(int i=0;i< getInstance().size();++i)
			{
			Column c= getInstance().get(i);
			if(c.isIgnore()) continue;
			if(c.getColumnIndex()>= this.tokens.length) continue;
			m.put(c.getId(), tokens[c.getColumnIndex()]);
			}
		return m;
		}
	String getURL()
		{
		ExprNode n= getInstance().getUrlExpr();
		if(n==null) return null;
		Context ctx=new Context(getInstance(), getTokens());
		n= n.eval(ctx);
		if(n==null) return null;
		return n.toString();
		}
	
	private void _writexmlcolumns(XMLStreamWriter w) throws XMLStreamException
		{
		for(int i=0;i< getInstance().size();++i)
			{
			Column c= getInstance().get(i);
			if(c.isIgnore()) continue;
			if(c.getColumnIndex()>= this.tokens.length) continue;
			w.writeStartElement(c.getId());
			w.writeCharacters(tokens[c.getColumnIndex()]);
			w.writeEndElement();
			}
		}
	
	/** write output for SOAP */
	public void writeSOAP(XMLStreamWriter w) throws XMLStreamException
		{
		w.writeStartElement(Instance.GENOMIC_OBJECT);
		w.writeAttribute(
				XSI.prefix,
				XSI.NS, "type",
				TNS.prefix+":"+instance.getTable().getXsdType()
				);
		_writexmlcolumns(w);
		w.writeEndElement();
		}
	
	}
